package com.marketmachine.brserver;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class BusinessRateServer {
	private static final String DB_CLASS_NAME = "com.mysql.jdbc.Driver";
	private static final String CONNECTION = "jdbc:mysql://127.0.0.1/businessrate";
	public static void main (String [] args) {
		new BusinessRateServer ().begin ();
	}

	public void begin () {
		
		try {
			Class.forName (DB_CLASS_NAME);
			Properties p = new Properties();
			p.put("user","james");
			p.put("password","sega10");
			//ResultSet priorRatings;
			//Connection conn = DriverManager.getConnection (CONNECTION, p);
			ServerSocket servSock = new ServerSocket (9379);
			System.out.println ("BEGINNING TO WAIT");
			while (true) {
				//Connection
				Socket client = servSock.accept();
				
				//Connection conn = DriverManager.getConnection (CONNECTION, p);
				System.out.println (client.getInetAddress ());
				/*PrintWriter pw = new PrintWriter (client.getOutputStream ());
				pw.write("HELLO WORLD");*/
				Connection conn = DriverManager.getConnection (CONNECTION, p);
				BufferedReader ratedata_buf = new BufferedReader (new InputStreamReader (client.getInputStream()));
				PrintWriter pw_addresses = new PrintWriter (client.getOutputStream (), true);
				//pw_addresses.println ("HELLOMOTO");
				String flag = ratedata_buf.readLine();
				System.out.println (flag);
				flag = flag.trim ();
				
				if (flag.equals ("w")){
					System.out.println ("ENTERED IF");
					boolean alreadyRated = false;
					int priorRating = -1;
					boolean foundAddr = false;
					String additional_desc = "";
					String addr = ratedata_buf.readLine ();
					String [] split_by_special_char = addr.split ("&");
					for (int x = 0; x < split_by_special_char.length; x++) {
						if (x == 0) {
							addr = "";
							addr = addr + split_by_special_char [x];
						} else {
							String possible_rem = split_by_special_char [x].substring (split_by_special_char [x].indexOf (";") + 1);
							addr = addr + possible_rem;
						}
					} //new
					addr = addr.replaceAll ("\'", "");
					String rating = ratedata_buf.readLine ();
					String phoneNum = ratedata_buf.readLine ();
					String additional_tags = ratedata_buf.readLine ();
					additional_tags = additional_tags.replaceAll ("\'", "");
					String given_choice = ratedata_buf.readLine ();
					given_choice = given_choice.replaceAll ("\'", "");
					String latlong = ratedata_buf.readLine ();
					System.out.println (given_choice);
					System.out.println (additional_tags);
					if (given_choice.equals ("null")) {
						additional_desc = additional_tags;
					} else  if (additional_tags.equals ("")){
						additional_desc = given_choice; 
					} else {
						additional_desc = given_choice + ", " + additional_tags;
					}
					System.out.println (additional_desc);
					System.out.println (addr);
					System.out.println (rating);
					System.out.println (phoneNum);
					Statement addRatingStatement = conn.createStatement ();
					ResultSet priorRatings = addRatingStatement.executeQuery("SELECT * FROM phonenumratingsmap");
					while (priorRatings.next ()) {
						String ratingPNum = priorRatings.getString ("PhoneNum");
						String bizRated = priorRatings.getString ("BusinessAddress");
						if (ratingPNum.equals (phoneNum) && bizRated.equals (addr)) {
							System.out.println ("ALREADY RATED");
							alreadyRated = true; 
							priorRating = priorRatings.getInt ("Rating");
							Statement updateStatement = conn.createStatement ();
							updateStatement.execute("UPDATE phonenumratingsmap SET Rating = " + rating + " WHERE Id = " + priorRatings.getRow());
						}
					}
					//priorRatings.close ();
					ResultSet currentRatings = addRatingStatement.executeQuery ("SELECT * FROM averageratings");
					while (currentRatings.next()) {
						String dbAddr = currentRatings.getString ("BusinessAddress");
						if (dbAddr.equals (addr)) {
							double currentAddrRate = currentRatings.getDouble ("AverageRating");
							int numRatings = currentRatings.getInt ("NumRatings");
							String current_desc = currentRatings.getString ("AdditionalDescription");
							current_desc = current_desc + ", " + additional_desc;
							float newAvr;
							Statement updateStatement = conn.createStatement ();
							if (alreadyRated == false) {
								newAvr  = (float) ((currentAddrRate * numRatings) + Integer.parseInt(rating)) / (numRatings + 1);
								
								updateStatement.execute("UPDATE averageratings SET AverageRating = " + newAvr + ", NumRatings = " + (numRatings + 1) + ", AdditionalDescription = \'" + current_desc +  "\'" + " WHERE Id = " + currentRatings.getRow ());
								updateStatement.execute("INSERT INTO phonenumratingsmap (PhoneNum, BusinessAddress, Rating) VALUES (\'" + phoneNum + "\', " + "\'" + addr + "\', " + rating + ")");
								
							} else {
								newAvr = (float) (((currentAddrRate * numRatings) - priorRating) + Integer.parseInt(rating)) / (numRatings);
								updateStatement.execute("UPDATE averageratings SET AverageRating = " + newAvr + ", AdditionalDescription = \'" + current_desc +  "\'" + " WHERE Id = " + currentRatings.getRow ());
							}
							
							foundAddr = true;
							
						}
					}
					if (foundAddr == false) {
						String searchableAddr = "";
						String [] addrComps = addr.split (" ");
						for (int x = 0; x < addrComps.length; x++) {
							searchableAddr = searchableAddr + addrComps[x].trim () + "s" + " " + addrComps[x].trim () + "es" + " ";
						}
						System.out.println (searchableAddr);
						addRatingStatement.execute("INSERT INTO averageratings (BusinessAddress, AverageRating, NumRatings, AdditionalDescription, LatLong, SearchableAddress) VALUES (\'" + addr + "\', " + rating + ", " + 1 + ", \'" + additional_desc + "\', \'" + latlong + "\', \'" + searchableAddr + "\'" + ")");
						addRatingStatement.execute("INSERT INTO phonenumratingsmap (PhoneNum, BusinessAddress, Rating) VALUES (\'" + phoneNum + "\', " + "\'" + addr + "\', " + rating + ")");
					}
					
				} else if (flag.equals ("r")) {
					String query = ratedata_buf.readLine ();
					String [] queryComps = query.split (" ");
					String provlatlong = ratedata_buf.readLine ();
					int maxmiles = Integer.parseInt (ratedata_buf.readLine ().trim ());
					
					String [] comps = provlatlong.split (",");
					double provlat = Double.parseDouble (comps[0].trim ());
					double provlon = Double.parseDouble (comps[1].trim ());
					String addresses = "";
					
					Statement retrieveRatingsStatement = conn.createStatement ();
					ResultSet currentRatings = retrieveRatingsStatement.executeQuery("SELECT * FROM averageratings");
					while (currentRatings.next ()) {
						
						String searchableAddr = currentRatings.getString ("SearchableAddress").toLowerCase ();
						System.out.println ("SEARCHABLEADDR " + searchableAddr);
						String add_desc = currentRatings.getString ("AdditionalDescription").toLowerCase ();
						System.out.println ("ADD_DESC " + add_desc);
						String latlong = currentRatings.getString ("LatLong");
						double currentRate = currentRatings.getDouble ("AverageRating");
						double lat = Double.parseDouble (latlong.split (",")[0].trim ());
						double lon = Double.parseDouble (latlong.split (",")[1].trim ());
						double distMiles = distBetweenCoordsMiles (provlat, provlon, lat, lon);
						if (distMiles <= maxmiles) {
							System.out.println ("DISTMILES UNDER MAXMILES");
							for (String comp : queryComps) {
								comp = comp.toLowerCase ();
								comp = comp.replaceAll ("\'", "");
								System.out.println ("COMP " + comp.trim ());
							if (comp.trim ().equals ("a") == false && comp.trim ().equals ("the") == false && comp.trim ().equals ("some") == false && comp.trim ().length () > 2){
								System.out.println ("ENTERED LINE IF_COMMON_WORDS_CHECK");
								if (add_desc.contains (comp.trim ())) {
									System.out.println ("SUCCESS");
								}
								if (searchableAddr.contains (comp.trim ()) || add_desc.contains (comp.trim ())) {
									System.out.println ("CONTAINS QUERY");
									if (addresses.equals ("")) {
										addresses = addresses + " >" + currentRatings.getString ("BusinessAddress") + "<" + currentRate + "<" + distMiles;
										break;
									} else {
										addresses = addresses + ">" + currentRatings.getString ("BusinessAddress") + "<" + currentRate + "<" + distMiles;
										break; //new
									}
								}
							}
						}
						
						
					}
				}
					System.out.println ("ADDRESSES = " + addresses);
					//PrintWriter pw_addresses = new PrintWriter (client.getOutputStream ());
					pw_addresses.println (addresses);
					pw_addresses.close ();
				

				//conn.close ();
			}
				conn.close ();
			
		}
		}catch (Exception e) {
			//conn.close ();
			e.printStackTrace();
			
		}
		
	}
	
	public static double distBetweenCoordsMiles (double lat1, double lon1, double lat2, double lon2) {
		return ((3958*3.1415926*Math.sqrt((lat2-lat1)*(lat2-lat1) + Math.cos(lat2/57.29578)*Math.cos(lat1/57.29578)*(lon2-lon1)*(lon2-lon1))/180)/1.609344);
	}
}
